import requests
import json
import base64
import hmac
import hashlib
import time
import os
from urllib.parse import urlencode
from ..exceptions import PlatformAPIException, PlatformRequestException, PlatformNotSupportSymbolException, PlatformClientException
from ..restapibase import RestAPIBase
from .symbols import symbols
from MarketData.const import CONST


class PoloniexRESTAPI(RestAPIBase):
    """docstring for BitfinexRESTAPI"""

    def __init__(self, api_key, secret_key, isdebug=False):
        self.api_key = api_key
        self.api_secret = secret_key
        self.isdebug = isdebug
        self.url = 'https://poloniex.com'

    def _debug(self, result):
        if self.isdebug:
            print(result)

    def _get_auth(self, data):
        payload = urlencode(data)
        signature = hmac.new(self.api_secret.encode(
            'utf-8'), payload.encode('utf-8'), hashlib.sha512).hexdigest()

        self._debug('payload: %s, signature: %s \n' % (payload, signature))

        headers = {
            'Key': self.api_key,
            'Sign': signature
        }

        return headers

    def _get(self, endpoint, params={}):
        url = self.url + endpoint
        self._debug(url)

        # headers = {'Accept': 'application/json',
        #            'Connection': 'Keep-Alive',
        #            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'}

        response = requests.get(url, params=params)
        self._debug(response.text)

        errmsg = 'StatusCode: GET %s \nURL:%s \nParams: %s \nResponse: %s' % (
            response.status_code, url, str(params), response.text)
        response = response.json()

        if response:
            if 'error' in response.keys():
                raise PlatformAPIException(errmsg)
            else:
                return response
        else:
            raise PlatformRequestException(errmsg)

    def _post(self, endpoint, data={}):
        url = self.url + endpoint
        self._debug(url)
        data['nonce'] = int(1000 * time.time())
        headers = self._get_auth(data)
        # headers.update({'Accept': 'application/json',
        #                 'Connection': 'Keep-Alive',
        #                 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'})

        response = requests.post(url, headers=headers, data=data)
        self._debug(response)
        self._debug(response.text)

        errmsg = 'StatusCode: POST %s \nURL:%s \nData: %s \nResponse: %s' % (
            response.status_code, url, str(data), response.text)
        response = response.json()

        if response:
            if 'error' in response.keys():
                raise PlatformAPIException(errmsg)
            else:
                return response
        else:
            raise PlatformRequestException(errmsg)

    # EndPoints

    # Market data
    def _symbols(self):
        url = '/public?command=returnTicker'

        resjson = self._get(url)
        self._debug('symbols: \n' + json.dumps(resjson, indent=2))

        result = []
        for symbol, ticker in resjson.items():
            result.append(symbol)
        sw = open(os.path.dirname(
            os.path.realpath(__file__)) + '/symbols.py', 'w')
        sw.write('symbols = ' + str(result))
        sw.close()
        self._debug('symbols: \n' + str(result))

        return result

    def _order(self, symbol='ETHBTC', side='buy', amount='0.04', price='0.044427'):

        url = '/tradingApi'

        data = {
            'command': side,
            'currencyPair': symbol,
            'rate': price,
            'amount': amount
        }

        result = self._post(url, data)
        return result

    # Public
    def get_currency(self, currency):
        return currency.upper()

    def get_symbol(self, commodity, base):
        result = base.upper() + '_' + commodity.upper()
        if not (result in symbols):
            errmsg = 'Not supported: %s' % result
            raise PlatformNotSupportSymbolException(errmsg)

        return result

    def get_ticker(self, symbol):
        url = '/public?command=returnTicker'

        result = self._get(url)
        self._debug('ticker: \n' + json.dumps(result, indent=2))
        return result

    def get_depth(self, symbol):
        url = '/public?command=returnOrderBook'

        params = {
            'currencyPair': symbol,
        }

        resjson = self._get(url, params)
        result = {}
        self._debug('get_depth: \n' + json.dumps(resjson, indent=2))

        bids = [{'price': bid[0], 'amount': bid[1]} for bid in resjson['bids']]
        asks = [{'price': ask[0], 'amount': ask[1]} for ask in resjson['asks']]
        result = {'bids': bids, 'asks': asks}

        self._debug('get_order_book: \n' + json.dumps(result, indent=2))
        return result

    # NotImplementedError
    def get_account(self):
        raise NotImplementedError()

    def get_balances(self, type='trade'):
        url = '/tradingApi'

        data = {
            'command': 'returnBalances'
        }

        result = self._post(url, data)
        self._debug('balance: \n' + json.dumps(result, indent=2))
        return result

    def limit_buy(self, symbol, amount, price):
        result = self._order(symbol, 'buy', amount, price)
        self._debug('limit_buy: \n' + json.dumps(result, indent=2))
        return result

    def limit_sell(self, symbol, amount, price):
        result = self._order(symbol, 'sell', amount, price)
        self._debug('limit_sell: \n' + json.dumps(result, indent=2))
        return result

    def market_buy(self, symbol, amount, price):
        result = self._order(symbol, 'buy', amount, "%.7f" % (
            float(price) * (1 + CONST.Slippage_synMarket)))
        self._debug('limit_sell: \n' + json.dumps(result, indent=2))
        return result

    def market_sell(self, symbol, amount, price):
        result = self._order(symbol, 'sell', amount, "%.7f" % (
            float(price) * (1 - CONST.Slippage_synMarket)))
        self._debug('limit_sell: \n' + json.dumps(result, indent=2))
        return result

    # NotImplementedError
    def get_order(self, symbol, order_id):
        raise NotImplementedError()

    # NotImplementedError
    def get_all_orders(self):
        raise NotImplementedError()

    def get_open_orders(self):
        url = '/tradingApi'

        data = {
            'command': 'returnOpenOrders',
        }

        result = self._post(url, data)
        self._debug('get_open_orders: \n' + json.dumps(result, indent=2))
        return result

    def cancel_order(self, symbol, order_id):
        url = '/tradingApi'

        data = {
            'command': 'cancelOrder',
            'orderNumber': order_id
        }

        result = self._post(url, data)
        self._debug('balance: \n' + json.dumps(result, indent=2))
        return result

    # NotImplementedError
    def cancel_all_orders(self):
        raise NotImplementedError()

    def withdraw(self, currency, amount, address):
        url = '/tradingApi'
        data = {
            "command": 'withdraw',
            "currency": currency,
            'amount': amount,
            "address": address,
        }

        result = self._post(url, data)
        self._debug('withdraw: \n' + json.dumps(result, indent=2))
        return result
